package net.towee.client.com.repo.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.towee.client.com.repo.presenter.RepositoryDocumentEditorPresenter.Display;
import net.towee.client.i18n.ToweeConstants;
import net.towee.client.resources.ClientResource;
import net.towee.client.widgets.ExtFlowPanel;
import net.towee.client.widgets.LeftTabsWidget;
import net.towee.client.widgets.ListItemWidget;
import net.towee.client.widgets.RichTextToolbar;
import net.towee.client.widgets.SheduledInputBox;
import net.towee.client.widgets.UnorderedListWidget;
import net.towee.client.widgets.upload.HasUploadHandlers;
import net.towee.client.widgets.upload.UploadError;
import net.towee.client.widgets.upload.UploadForm;
import net.towee.client.widgets.upload.UploadItem;
import net.towee.client.widgets.upload.UploadProgressHandler;
import net.towee.client.widgets.upload.UploadStartHandler;
import net.towee.client.widgets.upload.impl.UploadFormBasic;
import net.towee.client.widgets.upload.impl.UploadFormProvider;
import net.towee.client.widgets.upload.impl.UploadFormXHR;
import net.towee.model.repo.AttachmentIdentity;
import net.towee.model.repo.DocumentType;
import net.towee.model.utils.Pair;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

public class RepositoryDocumentEditorView extends FlowPanel implements Display, ClickHandler {
	private class RepoProfile extends FlowPanel {
		public final SheduledInputBox inputBox = new SheduledInputBox();
		public final FlowPanel nodesSelector = new FlowPanel();
		public final List<DocumentType> docTypes = new ArrayList<DocumentType>();
		public final List<Pair<TextBox, TextBox>> profileAreas = new ArrayList<Pair<TextBox, TextBox>>();

		private UnorderedListWidget typesContainer = new UnorderedListWidget();
		private FlowPanel fields = new FlowPanel();

		public RepoProfile() {
			typesContainer.setStyleName(resource.css().repoTypesContainer());

			// Create default fields
			fields.add(createField("Название", inputBox));
			fields.add(createField("Путь", nodesSelector));
			fields.add(createField("Типы", typesContainer));
			add(fields);

			// Create profile manager
			createProfileManager();
		}

		private void createProfileManager() {
			Button b = new Button("Добавить поле профиля");
			add(b);

			b.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					addProfileArea("", "");
				}
			});
		}

		public void addProfileArea(String key, String val) {
			TextBox name = new TextBox();
			TextBox value = new TextBox();
			name.getElement().setAttribute("key", "");

			name.setText(key);
			value.setText(val);

			final FlowPanel field = new FlowPanel();
			field.setStyleName(resource.css().repoField());
			field.add(name);
			field.add(value);
			fields.add(field);

			final Pair<TextBox, TextBox> rval = new Pair<TextBox, TextBox>(name, value);
			profileAreas.add(rval);

			Anchor del = new Anchor("Удалить");
			field.add(del);
			del.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					field.removeFromParent();
					profileAreas.remove(rval);
				}
			});
		}

		public void addType(DocumentType type) {
			if (!docTypes.contains(type)) {
				docTypes.add(type);

				ListItemWidget w = new ListItemWidget(constants.getString("DOCTYPE_" + type));
				typesContainer.add(w);
			}
		}
	}

	private class RepoDescription extends FlowPanel {
		public RichTextArea area = new RichTextArea();

		public RepoDescription() {
			RichTextToolbar tb = new RichTextToolbar(area);
			FlowPanel areaContainer = new FlowPanel();
			areaContainer.add(area);

			tb.setStyleName(resource.css().repoRichToolbar());
			areaContainer.setStyleName(resource.css().repoRichArea());

			add(tb);
			add(areaContainer);
		}

	}

	private class RepoFiles extends FlowPanel implements UploadStartHandler {
		public final UploadForm uploadForm;
		private final Label addLabel;
		public List<AttachmentIdentity> attachments = new ArrayList<AttachmentIdentity>();
		private Map<String, Widget> rawAttachments = new HashMap<String, Widget>();
		private int uploadedFiles = 0;

		public RepoFiles(UploadForm uploadForm) {
			this.uploadForm = uploadForm;
			uploadForm.setFilesNumberLimit(100);
			uploadForm.setMaxFileSize(100000000);
			
			addLabel = new Label(constants.repoAddLabelText());
			addLabel.setStyleName(resource.css().repoAddFileLabel());
			
			if( !uploadForm.isDropSupported() || Window.Navigator.getUserAgent().toLowerCase().contains("firefox") ) {
				FlowPanel container = new FlowPanel();
				container.setStyleName(resource.css().repoUploadInputContainer());
				container.add(uploadForm.getUploadInputWidget() );
				add(container);
				uploadForm.asWidget().getElement().getStyle().setProperty("top", "50px");
			}
			else 
				uploadForm.add(addLabel);
			
			add(uploadForm);
			uploadForm.asWidget().setStyleName(resource.css().repoUploadForm());
			uploadForm.addUploadStartHandler(this);
		}

		@Override
		public void onUploadingStarted(final UploadItem item) {
			addAttachedFile(null, item); 
		}

		@Override
		public void onOutOfLimit() {
		}

		public void onFileAttached(AttachmentIdentity att, String rawId) {
			if (rawAttachments.containsKey(rawId)) {
				uploadedFiles--;
				rawAttachments.get(rawId).getElement().setAttribute("done", "");
				rawAttachments.get(rawId).setLayoutData(att);
				rawAttachments.remove(rawId);
				attachments.add(att);
			}
		}

		public void addAttachedFile(AttachmentIdentity att) {
			addAttachedFile(att, null);
		}

		public void addAttachedFile(AttachmentIdentity att, final UploadItem item) {
			final ExtFlowPanel container = new ExtFlowPanel();
			container.setStyleName(resource.css().repoUploadItem());

			if (att != null) {
				attachments.add(att);
				container.setLayoutData(att);
			}	else {
				uploadedFiles++;
			}

			// Image preview container
			final FlowPanel forImage = new FlowPanel();
			forImage.getElement().setAttribute("preview", "");

			final FlowPanel forBody = new FlowPanel();
			forBody.getElement().setAttribute("body", "");
			container.add(forBody);

			// File name
			final ExtFlowPanel name = new ExtFlowPanel( (item != null) ? item.getFileName() : att.getName() );
			name.getElement().setAttribute("name", "");
			forBody.add(name);

			// Progress bar
			final FlowPanel progress = new FlowPanel();
			progress.getElement().setAttribute("progress", "");
			forBody.add(progress);

			uploadForm.add(container);
			addLabel.removeFromParent();

			container.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					container.removeFromParent();
					
					if(item != null)
						item.cancel();
					
					if(container.getLayoutData() != null)
						attachments.remove(container.getLayoutData());
				}
			});

			if (item != null) {
				item.setProgressHandler(new UploadProgressHandler() {
					@Override
					public void onDataURLReed(String dataUrl) {
						Image img = new Image(dataUrl);
						forImage.add(img);
						container.addFirst(forImage);
					}

					@Override
					public void onCompleteUploading(String response) {
						rawAttachments.put(response, container);
						progress.removeFromParent();
					}

					@Override
					public void onUploadItemQueued() {

					}

					@Override
					public void onProgressUpdated(int percents, long loadedBytes, long allBytes) {
						progress.setWidth(percents + "%");
					}

					@Override
					public void onErrorUploading(UploadError error) {
						uploadedFiles--;
					}

					@Override
					public void onCancelUploading() {
						uploadedFiles--;
					}

					@Override
					public void onUploadingStarted(boolean b) {
						if (!b)
							progress.setWidth("100%");
					}
				});

				// Start uploading
				item.start();
			}
		}

		public boolean isAllFilesAttached() {
			return uploadedFiles <= 0;
		}
	}
	
	private class ExplanationPanel extends FlowPanel {
		public TextArea area = new TextArea();
		
		public ExplanationPanel() {
			setStyleName( resource.css().repoDocumentExplanationPanel() );
			add(new ExtFlowPanel( constants.repoDocumentChangeExpl() ));
			add(area);
			add(createButton);
			
			createButton.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					// Remove popup
					((PopupPanel)(getParent())).hide();
				}
			});
		}
	}

	private final ToweeConstants constants;
	private final ClientResource resource;

	private final Button createButton = new Button();
	private final Button cancelButton = new Button();

	private final RepoProfile profile;
	private final RepoDescription description;
	private final RepoFiles files;
	private final FlowPanel tabContainer = new FlowPanel();
	private ExplanationPanel explanation;
	private Widget currentActiveTab;

	@Inject
	public RepositoryDocumentEditorView(ToweeConstants constants, ClientResource resource,
			UploadForm uplform) {
		this.constants = constants;
		this.resource = resource;

		this.description = new RepoDescription();
		this.files = new RepoFiles( uplform );
		this.profile = new RepoProfile();

		createTabs();
		createButtons();
		createErrorContainer();
	}

	private void createErrorContainer() {
		
	}

	private void createButtons() {
		FlowPanel buttons = new FlowPanel();
		buttons.add(createButton);
		buttons.add(cancelButton);
		add(buttons);

		createButton.setText(constants.create());
		cancelButton.setText(constants.cancel());

		createButton.setStyleName(resource.css().lobbyNextStepButton());
		cancelButton.setStyleName(resource.css().lobbyCloseButton());

		buttons.setStyleName(resource.css().repoDocumentEditorButtons());
	}
	
	public void setEditMode() {
		FlowPanel buttons = (FlowPanel)createButton.getParent();
		createButton.setText( constants.change() );
		createButton.removeFromParent();
		
		// Create expl panel
		explanation = new ExplanationPanel();
		
		// Create a basic popup widget
	    final PopupPanel simplePopup = new PopupPanel(true);
	    simplePopup.setWidget( explanation );
	    simplePopup.setGlassEnabled(true);
	    simplePopup.setGlassStyleName( resource.css().loadingBarGlass() );
	    simplePopup.getElement().getStyle().setZIndex(10000000);

	    // Create a button to show the popup
	    simplePopup.setStyleName("");
	    simplePopup.getElement().getStyle().setBackgroundColor("white");
	    Button openButton = new Button(constants.change(), new ClickHandler() {
	          public void onClick(ClickEvent event) {
	            // Reposition the popup relative to the button
	            Widget source = (Widget) event.getSource();
	            int left = source.getAbsoluteLeft() + 180;
	            int top = source.getAbsoluteTop() -100;
	            simplePopup.setPopupPosition(left, top);

	            // Show the popup
	            simplePopup.show();
	          }
	        });
	    openButton.setStyleName(resource.css().lobbyNextStepButton());
	    buttons.add( openButton );
	}

	private void createTabs() {
		LeftTabsWidget navigation = new LeftTabsWidget(resource);
		add(navigation);

		// Profile tab
		Widget w = navigation.addTab(constants.repoProfile(), true);
		w.setLayoutData(profile);
		((HasClickHandlers) w).addClickHandler(this);

		// Description tab
		w = navigation.addTab(constants.repoDescription());
		w.setLayoutData(description);
		((HasClickHandlers) w).addClickHandler(this);

		// Files tab
		w = navigation.addTab(constants.repoFiles());
		w.setLayoutData(files);
		((HasClickHandlers) w).addClickHandler(this);

		tabContainer.add(profile);
		tabContainer.add(description);
		tabContainer.add(files);
		add(tabContainer);

		currentActiveTab = profile;
		description.setVisible(false);
		files.setVisible(false);

		tabContainer.setStyleName(resource.css().repoDocumentEditorTabsContainer());
		navigation.addStyleName(resource.css().repoDocumentEditorTabs());
	}

	@Override
	public void onClick(ClickEvent event) {
		Widget tab = (Widget) ((Widget) (event.getSource())).getLayoutData();
		currentActiveTab.setVisible(false);
		tab.setVisible(true);
		currentActiveTab = tab;
	}

	private Widget createField(String name, Widget w) {
		FlowPanel field = new FlowPanel();
		field.setStyleName(resource.css().repoField());
		field.add(new ExtFlowPanel(name, resource.css().repoFieldName()));
		field.add(w);
		return field;
	}

	@Override
	public HasClickHandlers getCreateButton() {
		return createButton;
	}

	@Override
	public HasClickHandlers getCancelButton() {
		return cancelButton;
	}

	@Override
	public HasChangeHandlers getNameInputBox() {
		return profile.inputBox;
	}

	@Override
	public HasUploadHandlers getUploadForm() {
		return files.uploadForm;
	}

	@Override
	public HasWidgets getContainerForNodeSelector() {
		return profile.nodesSelector;
	}

	@Override
	public List<DocumentType> getTypes() {
		return profile.docTypes;
	}

	@Override
	public List<Pair<String, String>> getProfileAreas() {
		List<Pair<String, String>> result = new ArrayList<Pair<String, String>>();

		for (Pair<TextBox, TextBox> area : profile.profileAreas) {
			result.add(new Pair<String, String>(area.getFirst().getText(), area.getSecond().getText()));
		}

		return result;
	}

	@Override
	public String getDescription() {
		return description.area.getHTML();
	}

	@Override
	public String getName() {
		return profile.inputBox.getText().trim();
	}

	@Override
	public List<AttachmentIdentity> getAtachments() {
		return files.attachments;
	}

	@Override
	public String getExplanation() {
		return explanation.area.getText().trim();
	}

	@Override
	public void addType(DocumentType type) {
		profile.addType(type);
	}

	@Override
	public void addProfileArea(String key, String value) {
		profile.addProfileArea(key, value);
	}

	@Override
	public void setDescription(String descr) {
		description.area.setHTML(descr);
	}

	@Override
	public void setName(String name) {
		profile.inputBox.setText(name.trim());
	}

	@Override
	public void addAttachment(AttachmentIdentity att) {
		files.addAttachedFile(att);
	}

	@Override
	public void addAttachment(AttachmentIdentity att, String rawId) {
		files.onFileAttached(att, rawId);
	}

	@Override
	public void nameTooShort(int minLength) {
		// TODO Auto-generated method stub

	}

	@Override
	public void nameExists() {
		// TODO Auto-generated method stub

	}

	@Override
	public void descTooShort(int minLength) {
		// TODO Auto-generated method stub

	}

	@Override
	public void explTooShort(int minExplLength) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean hasErrors() {
		return false;
	}

	@Override
	public void setDocumentType(DocumentType type) {
		profile.docTypes.clear();
		profile.typesContainer.clear();
		profile.addType( type );
	}

	@Override
	public boolean isFilesAttached() {
		return files.isAllFilesAttached();
	}
}
